package test;

import lombok.AllArgsConstructor;
import lombok.Getter;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;

/**
 * 签名示例代码
 */
public class Demo {
    private static String ALG_AES = "AES/ECB/PKCS5Padding";
    private static String NAME_AES = "AES";


    static String ak = "XXXXXXXXX";
    static String aks = "XXXXXXXXX";

    public static void main(String[] args) throws Exception {
        economicCapability();
    }

    public static void economicCapability() throws Exception {
        SignInfo s = sign(ak, aks);

        String urlPath = String.format("http://teklcn.cn/szsys/economy/person?ak=%s&sign=%s&time=%d&alg=%s&ver=%s"
                , s.getAk()
                , URLEncoder.encode(s.getSign(), "UTF-8")
                , s.getTime()
                , s.getAlg()
                , s.getVer());

        String param = "{\n" +
                "    \"code\": \"xxxx\",\n" +
                "    \"idCard\": \"51XXXXXXXXXXXXXX\",\n" +
                "    \"name\": \"张xx\",\n" +
                "    \"mobile\": \"182XXXXXXXX\"\n" +
                "}";

        //将业务参数转换成请求参数
        String encryptParam = "{\n" +
                "   \"encryptData\":\"" + aesEncode(param, aks) + "\"\n" +
                "}";
        //建立连接
        URL url = new URL(urlPath);
        //如果需要添加证书此处返回HttpsURLConnection，使用setSSLSocketFactory()
        //以及涉及是否验证服务器setHostnameVerifier，默认false，false为验证，也可以根据参数的实现方法的第一个参数选择是否验证，即HostnameVerifier(){@Override Public boolean verify(String arg0,SSLSession arg1){return true;}}
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();

        //设置参数
        httpConn.setDoOutput(true);
        httpConn.setDoInput(true);
        httpConn.setUseCaches(false);
        httpConn.setRequestMethod("POST");

        //设置请求属性
        httpConn.setRequestProperty("Content-Type", "application/json");
        httpConn.setRequestProperty("Connection", "Keep-Alive");
        httpConn.setRequestProperty("Charset", "UTF-8");

        httpConn.connect();

        DataOutputStream dos = new DataOutputStream(httpConn.getOutputStream());
        dos.write(encryptParam.getBytes());
        dos.flush();
        dos.close();

        //获得响应状态
        int resultCode = httpConn.getResponseCode();
        if (HttpURLConnection.HTTP_OK == resultCode) {
            StringBuffer sb = new StringBuffer();
            String readLine;
            BufferedReader responseReader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), "UTF-8"));
            while ((readLine = responseReader.readLine()) != null) {
                sb.append(readLine).append("\n");
            }
            responseReader.close();
            System.out.println(sb);
        }
    }


    static SignInfo sign(String ak, String aks) {
        long time = System.currentTimeMillis();
        char[] chs = (ak + time).toCharArray();
        Arrays.sort(chs);
        String src = new String(chs);
        return new SignInfo(ak, aesEncode(src, aks), time, "1", "1", System.currentTimeMillis() + "");
    }

    static String aesEncode(String source, String key) {
        String AES_encode = null;
        try {
            byte[] byte_AES = getCipher(key, Cipher.ENCRYPT_MODE).doFinal(str2Bytes(source));
            AES_encode = new String(base64Encode(byte_AES));
            return AES_encode;
        } catch (Exception e) {
            System.out.println("加密失败:" + e.getMessage());
        }
        return AES_encode;
    }

    private static Cipher getCipher(String key, int mode) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException {
        KeyGenerator keyGen = KeyGenerator.getInstance(NAME_AES);
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        sr.setSeed(str2Bytes(key));
        keyGen.init(128, sr);
        SecretKey secKey = keyGen.generateKey();
        byte[] raw = secKey.getEncoded();

        Cipher cipher = Cipher.getInstance(ALG_AES);
        cipher.init(mode, new SecretKeySpec(raw, NAME_AES));
        return cipher;
    }

    private static byte[] str2Bytes(String str) {
        return str.getBytes(StandardCharsets.UTF_8);
    }


    /**
     * 转换为base64编码
     *
     * @param bs
     * @return
     */
    public static String base64Encode(byte[] bs) {
        return new String(Base64.getEncoder().encode(bs), StandardCharsets.UTF_8);
    }

    @Getter
    @AllArgsConstructor
    static class SignInfo {
        String ak;//key
        String sign;//签名
        Long time;
        String alg;
        String ver;
        String requestId;
    }
}
